#pragma once

#include "templates.h"

#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <fstream>

namespace example
{

inline void inserting_using_const_iterator()
{
    typedef std::vector<int> vector_t;
    vector_t v = { 1, 2, 3, 4, 5 };

    vector_t::const_iterator c_it = std::find(v.begin(), v.end(), 3);
    // v.insert(c_it, 99); // not work because c_it is const_iterator

    // another way
    vector_t::iterator it(v.begin());
    // not compiled because distance is a template - args are of different types so compiler can't determine template parametr, so
    // std::advance(it, std::distance(it, c_it));
    std::advance(it, std::distance<decltype(c_it)>(it, c_it));
    v.insert(it, 99); // not work because c_it is const_iterator

    print_vector(v);
}

inline void inserting()
{
    std::vector<int> v = { 1, 2, 3, 4, 5 };

    auto it = std::find(v.begin(), v.end(), 3);

    v.insert(it, 99);

    print_vector(v);
}

inline void erasing()
{
    std::vector<int> v = { 1, 2, 3, 4, 5 };

    auto it = std::find(v.begin(), v.end(), 3);

    v.erase(it);

    print_vector(v);
}

inline void reverse_inserting()
{
    std::vector<int> v = { 1, 2, 3, 4, 5 };

    auto rev_it = std::find(v.rbegin(), v.rend(), 3);

    std::cout << "reverse iterator = " << *rev_it << "; rev_it.base() = " << *(rev_it.base()) << std::endl;

//    v.insert(it, 99); // it's bad - should use iterator for inserting (not reverse_iterator)
    v.insert(rev_it.base(), 99);

    print_vector(v);
}

inline void reverse_erasing()
{
    std::vector<int> v = { 1, 2, 3, 4, 5 };

    auto rev_it = std::find(v.rbegin(), v.rend(), 3);

    v.erase((++rev_it).base());  // this erase 3 from vector, as we expected!

    print_vector(v);
}


inline void istream_iterator_using()
{
    std::ifstream input_file("/home/vintik/projects/stl-examples/project/iterators.h");

    // std::string data(std::istream_iterator<char>(input_file), std::istream_iterator<char>()); // this is function declaration

    // in this case we lost whitespaces
    // std::string data((std::istream_iterator<char>(input_file)), std::istream_iterator<char>()); // () for args in declaration can't use, but can used when call function

    input_file.unsetf(std::ios_base::skipws);
    std::string data_all((std::istream_iterator<char>(input_file)), std::istream_iterator<char>());

    std::cout << data_all << std::endl;
}

inline void istreambuf_iterator_using()
{
    std::ifstream input_file("/home/vintik/projects/stl-examples/project/iterators.h");

    input_file.unsetf(std::ios_base::skipws);
    std::string data((std::istreambuf_iterator<char>(input_file)), std::istreambuf_iterator<char>());

    std::cout << data << std::endl;
}

} // end of namespace example
